﻿namespace EFS.RC.CC.Presences.EndPoints
{
	/// <summary>
	/// End points presence list
	/// </summary>
	internal class Registrar : EFS.Common.ISelfDescriptor 
	{
		#region Private components

		// Async access
		private object syncAccess = new object();

		/// Office end point presence
		private EFS.RC.CC.Presences.EndPoints.OfficeService.Operator operatorsOfficeServiceEndPointPresence = null;

		/// Direct Dial end point presence
		private EFS.RC.CC.Presences.EndPoints.OfficeService.DirectDial directDialOfficeServiceEndPointPresence = null;

		// Customer End points
		private System.Collections.Generic.Dictionary<System.String, EFS.RC.CC.Presences.EndPoints.OfficeService.Customer> customerOfficeServicePresencesDictionary =
			new System.Collections.Generic.Dictionary<System.String, EFS.RC.CC.Presences.EndPoints.OfficeService.Customer>(System.StringComparer.OrdinalIgnoreCase);

		#endregion

		#region Constructor

		/// <summary>
		/// Constructor
		/// </summary>
		public Registrar(){}

		#endregion

		#region Delegates

		/// <summary>
		/// Customer OfficeService EndPoint Presence callback
		/// </summary>
		public delegate void CustomerOfficeServiceEndPointPresenceCallback(EFS.RC.CC.Presences.EndPoints.OfficeService.Customer customerOfficeServiceEndPointPresence);

		#endregion

		#region Usage

		/// <summary>
		/// Get Operators Office Service End Point Presence
		/// </summary>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.Operator OperatorOfficeServiceEndPointPresence
		{
			get 
			{ 
				// check
				EFS.Common.Verify.Reference(operatorsOfficeServiceEndPointPresence, "Operators End Point is not avilable");
				return operatorsOfficeServiceEndPointPresence; 
			}
		}

		/// <summary>
		/// Get DirectDial Office Service End Point Presence
		/// </summary>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.DirectDial DirectDialOfficeServiceEndPointPresence
		{
			get
			{
				// check
				EFS.Common.Verify.Reference(directDialOfficeServiceEndPointPresence, "DirectDial End Point is not avilable");
				return directDialOfficeServiceEndPointPresence;
			}
		}

		/// <summary>
		/// Register Office end point deployment
		/// </summary>
		/// <param name="endPointDeployment"></param>
		/// <returns></returns>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.Operator RegisterOfficeEndPointDeployment(EFS.RC.CC.Deployment.Entities.EndPoints.Office officeEndPointDeployment)
		{
			// log
			EFS.EventLog.Log.LogInfo("RegisterOfficeEndPointDeployment", this);

			// check
			EFS.Common.Verify.Reference(officeEndPointDeployment, "officeEndPointDeployment");

			// lock access to our list
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// check already in
				if (null != operatorsOfficeServiceEndPointPresence)
				{
					throw new System.Exception(System.String.Format("Office EndPoint Deployemnt already registered"));
				}

				// make new
				operatorsOfficeServiceEndPointPresence = new EFS.RC.CC.Presences.EndPoints.OfficeService.Operator(this, officeEndPointDeployment);
			}

			// get presence
			return operatorsOfficeServiceEndPointPresence;
		}

		/// <summary>
		/// Register DirectDial end point deployment
		/// </summary>
		/// <param name="endPointDeployment"></param>
		/// <returns></returns>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.DirectDial RegisterDirectDialEndPointDeployment(EFS.RC.CC.Config.DirectDialDeployment gateEndPointDeployment)
		{
			// log
			EFS.EventLog.Log.LogInfo("RegisterDirectDialEndPointDeployment", this);

			// check
			EFS.Common.Verify.Reference(gateEndPointDeployment, "gateEndPointDeployment");

			// lock access to our list
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// check already in
				if (null != directDialOfficeServiceEndPointPresence)
				{
					throw new System.Exception(System.String.Format("DirectDial EndPoint Deployemnt already registered"));
				}

				// make new
				directDialOfficeServiceEndPointPresence = new EFS.RC.CC.Presences.EndPoints.OfficeService.DirectDial(this, gateEndPointDeployment);
			}

			// get presence
			return directDialOfficeServiceEndPointPresence;
		}

		/// <summary>
		/// Register end point deployment
		/// </summary>
		/// <param name="endPointDeployment"></param>
		/// <returns></returns>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.Operator UnRegisterOperatorOfficeServicePresence()
		{
			// log
			EFS.EventLog.Log.LogInfo("UnRegisterCustomerEndPointDeployment", this);

			// lock access to our list
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// check already in
				if (null != this.operatorsOfficeServiceEndPointPresence)
				{
					// keep
					EFS.RC.CC.Presences.EndPoints.OfficeService.Operator operatorsOfficeServiceEndPointPresence = this.operatorsOfficeServiceEndPointPresence;

					// keep
					this.operatorsOfficeServiceEndPointPresence = null;

					// done
					return operatorsOfficeServiceEndPointPresence;
				}
			}

			// not registered
			return null;
		}

		/// <summary>
		/// Register end point deployment
		/// </summary>
		/// <param name="endPointDeployment"></param>
		/// <returns></returns>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.DirectDial UnRegisterDirectDialOfficeServicePresence()
		{
			// log
			EFS.EventLog.Log.LogInfo("UnRegisterCustomerEndPointDeployment", this);

			// lock access to our list
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// check already in
				if (null != this.directDialOfficeServiceEndPointPresence)
				{
					// keep
					EFS.RC.CC.Presences.EndPoints.OfficeService.DirectDial directDialOfficeServiceEndPointPresence = this.directDialOfficeServiceEndPointPresence;

					// keep
					this.directDialOfficeServiceEndPointPresence = null;

					// done
					return directDialOfficeServiceEndPointPresence;
				}
			}

			// not registered
			return null;
		}

		/// <summary>
		/// Register Customer end point deployment
		/// </summary>
		/// <param name="endPointDeployment"></param>
		/// <returns></returns>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.Customer RegisterCustomerEndPointDeployment(EFS.RC.CC.Deployment.Entities.EndPoints.Customer customerEndPointDeployment)
		{
			// log
			EFS.EventLog.Log.LogInfo("RegisterCustomerEndPointDeployment", this);

			// check
			EFS.Common.Verify.Reference(customerEndPointDeployment, "customerEndPointDeployment");

			// presence
			EFS.RC.CC.Presences.EndPoints.OfficeService.Customer customersOfficeServiceEndPointPresence = null;

			// lock access to our list
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// check already in
				if (customerOfficeServicePresencesDictionary.ContainsKey(customerEndPointDeployment.URI))
				{
					throw new System.Exception(System.String.Format("EndPoint Presence already added for {0}", customerEndPointDeployment.URI));
				}

				// make new
				customersOfficeServiceEndPointPresence = new EFS.RC.CC.Presences.EndPoints.OfficeService.Customer(this, customerEndPointDeployment);

				// add endPoint
				customerOfficeServicePresencesDictionary.Add(customerEndPointDeployment.URI, customersOfficeServiceEndPointPresence);
			}

			// get presence
			return customersOfficeServiceEndPointPresence;
		}

		/// <summary>
		/// Register end point deployment
		/// </summary>
		/// <param name="endPointDeployment"></param>
		/// <returns></returns>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.Customer UnRegisterCustomerOfficeServicePresence(System.String uri)
		{
			// log
			EFS.EventLog.Log.LogInfo("UnRegisterCustomerEndPointDeployment", this);

			// check
			EFS.Common.Verify.String(uri, "ownerUri");

			// presence
			EFS.RC.CC.Presences.EndPoints.OfficeService.Customer customersOfficeServiceEndPointPresence = null;

			// lock access to our list
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// check already in
				if (!customerOfficeServicePresencesDictionary.ContainsKey(uri))
				{
					throw new System.Exception(System.String.Format("EndPoint Presence not registered {0}", uri));
				}

				// keep
				customersOfficeServiceEndPointPresence = customerOfficeServicePresencesDictionary[uri];

				// remove
				customerOfficeServicePresencesDictionary.Remove(uri);
			}

			// get presence
			return customersOfficeServiceEndPointPresence;
		}

		/// <summary>
		/// Register end point deployment
		/// </summary>
		/// <param name="endPointDeployment"></param>
		/// <returns></returns>
		public System.Collections.Generic.List<EFS.RC.CC.Presences.EndPoints.OfficeService.Customer> UnRegisterAllCustomerOfficeServicePresences()
		{
			// log
			EFS.EventLog.Log.LogInfo("UnRegisterAllCustomerEndPointDeployments", this);

			// presence
			System.Collections.Generic.List<EFS.RC.CC.Presences.EndPoints.OfficeService.Customer> customersOfficeServiceEndPointPresenceList = new System.Collections.Generic.List<EFS.RC.CC.Presences.EndPoints.OfficeService.Customer>();

			// lock access to our list
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// add to list
				foreach(EFS.RC.CC.Presences.EndPoints.OfficeService.Customer customersOfficeServiceEndPointPresence in customerOfficeServicePresencesDictionary.Values)
				{
					customersOfficeServiceEndPointPresenceList.Add(customersOfficeServiceEndPointPresence);
				}

				// remove all
				customerOfficeServicePresencesDictionary.Clear();
			}

			// get presence
			return customersOfficeServiceEndPointPresenceList;
		}

		/// <summary>
		/// Get presence by uri
		/// </summary>
		/// <param name="uri"></param>
		/// <returns></returns>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.Customer GetGatewayCustomerOfficeServicePresence()
		{
			// log
			EFS.EventLog.Log.LogInfo("GetPresence", this);

			// lock
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// call back for each
				foreach (EFS.RC.CC.Presences.EndPoints.OfficeService.Customer customersOfficeServiceEndPointPresence in customerOfficeServicePresencesDictionary.Values)
				{
					// check
					return customersOfficeServiceEndPointPresence;
				}
			}

			// none
			return null;
		}

		/// <summary>
		/// Get presence by uri
		/// </summary>
		/// <param name="uri"></param>
		/// <returns></returns>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.Customer GetCustomerOfficeServicePresence(System.String uri)
		{
			// log
			EFS.EventLog.Log.LogInfo("GetPresence", this);

			// lock
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// check already in
				if (!customerOfficeServicePresencesDictionary.ContainsKey(uri))
				{
					return null;
				}

				// get it
				return customerOfficeServicePresencesDictionary[uri];
			}
		}

		/// <summary>
		/// Get presence by uri
		/// </summary>
		/// <param name="uri"></param>
		/// <returns></returns>
		public void ForeachCustomerOfficeServicePresence(CustomerOfficeServiceEndPointPresenceCallback customerOfficeServiceEndPointPresenceCallback)
		{
			// log
			EFS.EventLog.Log.LogInfo("ForeachCustomerOfficeServicePresence", this);

			// check
			EFS.Common.Verify.Reference(customerOfficeServiceEndPointPresenceCallback, "customerOfficeServiceEndPointPresenceCallback");

			// local array
			EFS.RC.CC.Presences.EndPoints.OfficeService.Customer[] customersOfficeServiceEndPointPresenceArray = null;
			
			// lock to access instance dictionary
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// init arrray
				customersOfficeServiceEndPointPresenceArray = new EFS.RC.CC.Presences.EndPoints.OfficeService.Customer[customerOfficeServicePresencesDictionary.Values.Count];

				// copy
				customerOfficeServicePresencesDictionary.Values.CopyTo(customersOfficeServiceEndPointPresenceArray, 0);
			}

			// call back for each
			foreach (EFS.RC.CC.Presences.EndPoints.OfficeService.Customer customersOfficeServiceEndPointPresence in customersOfficeServiceEndPointPresenceArray)
			{
				// check
				customerOfficeServiceEndPointPresenceCallback(customersOfficeServiceEndPointPresence);
			}
		}

		/// <summary>
		/// Get presence by uri
		/// </summary>
		/// <param name="uri"></param>
		/// <returns></returns>
		public EFS.RC.CC.Presences.EndPoints.OfficeService.Customer GetCustomerOfficeServicePresence(System.Int32 endPointDeploymentId)
		{
			// log
			EFS.EventLog.Log.LogInfo("GetPresence", this);

			// lock
			// ~ commented for performance ~  EFS.EventLog.Log.LogExtended("Entering lock", new System.Diagnostics.StackTrace());
			lock (syncAccess)
			{
				// check already in
				foreach(EFS.RC.CC.Presences.EndPoints.OfficeService.Customer customersOfficeServiceEndPointPresence in customerOfficeServicePresencesDictionary.Values)
				{
					// check
					if (customersOfficeServiceEndPointPresence.PresenceEndPointDeployment.ID == endPointDeploymentId)
					{
						return customersOfficeServiceEndPointPresence;
					}
				}
			}
			
			// not here
			return null;
		}

		/// <summary>
		/// Describe this
		/// </summary>
		/// <returns></returns>
		public virtual System.String Describe()
		{
			return System.String.Format("EFS.RC.CC.Presences.EndPoints.Registrar");
		}

		#endregion
	}
}
